﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BO.Management.QueryBuilder
{
    public class InfoStoreQuery
    {

        public InfoStoreQuery(String tableName)
        {
            this.TableName = tableName;
            this.FilterParameters = new QueryParameters();
            this.Fields = new List<string>();
            this.Limit = 0;
        }

        public InfoStoreQuery(String tableName, QueryParameters parameters)
        {
            this.TableName = tableName;
            this.FilterParameters = new QueryParameters();
            if (parameters != null) this.FilterParameters.AddRange(parameters);
            this.Fields = new List<string>();
            this.Limit = 0;
        }


        public String TableName { get; private set; }
        public QueryParameters FilterParameters { get; private set; }

        public Int32 Limit { get; private set; }

        public List<String> Fields { get; private set; }

        /// <summary>
        /// Add a filter parameter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameterName"></param>
        /// <param name="oper"></param>
        /// <param name="value"></param>
        public void AddParameter<T>(String parameterName, OperatorType oper, T value)
        {
            this.FilterParameters.Add(
                new QueryParameter<T>()
                {
                    ParameterName = parameterName.ToUpper(),
                    Operator = oper,
                    Value = value
                }
            );
        }

        /// <summary>
        /// Change a filter parameter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parameterName"></param>
        /// <param name="oper"></param>
        /// <param name="value"></param>
        public void ChangeParameter<T>(String parameterName, OperatorType oper, T value)
        {

            var existingParameters = from param in this.FilterParameters
                                     where param.ParameterName.ToUpper() == parameterName
                                     select param;

            BaseQueryParameter existingParameter = existingParameters.FirstOrDefault();
            if (existingParameter != null && this.FilterParameters.Contains(existingParameter))
            {
                this.FilterParameters.Remove(existingParameter);
            }

            this.AddParameter<T>(parameterName, oper, value);
        }


        /// <summary>
        /// Add a query field
        /// </summary>
        /// <param name="fieldName"></param>
        public void AddField(String fieldName)
        {
            var existingField = from param in this.Fields
                                where param.ToUpper() == fieldName.ToUpper()
                                select param;


            if (existingField.Count() > 0) return;

            this.Fields.Add(fieldName.ToUpper());

        }


        public void AddLimit(Int32 limit)
        {
            this.Limit = limit;
        }


        public void RemoveLimit(Int32 limit)
        {
            this.Limit = 0;
        }

        /// <summary>
        /// Get the query used to retrieve objects
        /// </summary>
        /// <returns></returns>
        public String GetQuery()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Select ");

            if (this.Limit > 0)
            {
                sb.AppendFormat(" TOP {0} ", this.Limit);
            }

            if (this.Fields.Count == 0) sb.AppendFormat("*");
            else
            {
                Int32 count = 0;
                foreach (String field in this.Fields)
                {
                    count++;
                    sb.AppendFormat(field);
                    if (count < this.Fields.Count)
                        sb.AppendFormat(",");
                }
            }

            sb.AppendFormat(" From {0}", this.TableName);
            String filter = this.GetFilter();
            if (!String.IsNullOrEmpty(filter))
            {
                sb.Append(" ");
                sb.Append(filter);
            }
            return sb.ToString();
        }


        /// <summary>
        /// Get the filter used to retrieve objects
        /// </summary>
        /// <returns></returns>
        public String GetFilter()
        {
            StringBuilder sb = new StringBuilder();
            if (this.FilterParameters.Count > 0)
            {
                Boolean first = true;
                foreach (BaseQueryParameter parameter in this.FilterParameters)
                {
                    if (first)
                    {
                        first = false;
                        sb.AppendFormat("WHERE {0}", parameter.ToString());
                    }
                    else
                    {
                        sb.AppendFormat(" AND {0}", parameter.ToString());
                    }
                }
            }
            return sb.ToString();
        }

    }
}
